package com.ideaaedi.springcloud.jd.commonspring.oauth2;

import com.ideaaedi.springcloud.jd.commonspring.util.JdContextUtil;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

/**
 * 自定义认证管理器
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2021.0.5.B
 */
@SuppressWarnings("deprecation")
public class CustomOAuth2AuthenticationManager extends OAuth2AuthenticationManager {
    
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    
    private final Set<String> permitAllUrls = new HashSet<>();
    
    public CustomOAuth2AuthenticationManager(Collection<String> permitAllUrls) {
        if (CollectionUtils.isEmpty(permitAllUrls)) {
            return;
        }
        this.permitAllUrls.addAll(permitAllUrls);
    }
    
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        try {
            return super.authenticate(authentication);
        } catch (AuthenticationException | InvalidTokenException e) {
            HttpServletRequest httpServletRequest = JdContextUtil.getHttpServletRequest();
            if (httpServletRequest == null) {
                throw e;
            }
            String requestUri = httpServletRequest.getRequestURI();
            boolean hasPermission = permitAllUrls.stream().anyMatch(x -> antPathMatcher.match(x, requestUri));
            if (hasPermission) {
                // bugfix：如果token过期了或者token错误了，请求开放的接口是会被看拦截的
                return new AnonymousAuthenticationToken(UUID.randomUUID().toString(), "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
            }
            throw e;
        }
    }
}